package com.hymjweb.demo.framework.util.pojoContrast;

/**
 * @author DaTing created on 2020-09-12
 **/

import com.alibaba.fastjson.JSONObject;
import com.hymjweb.demo.framework.cache.service.GlobalCacheService;
import com.hymjweb.demo.framework.sys.BaseService;
import com.hymjweb.demo.framework.sys.SysConstant;
import com.hymjweb.demo.framework.util.DataTypeUtil;
import com.hymjweb.demo.framework.util.DateUtil;
import com.hymjweb.demo.framework.util.RegexUtil;
import com.hymjweb.demo.hymj.log_manage.data_column.service.DataColumnService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.Table;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;

/**
 * @Description: 比较两个对象的变化
 */

@Service
public class ContrastUtils extends BaseService {

    public static final String BR = "<BR>";

    public static final String EMPTY_STR_VALUE = "空";

    /**如果注释中出现这样的关键字，则不用翻译*/
    public static final String NOT_NEED_TRANSLATE_COMMENT_KEYS = "不用翻译,不翻译";

    /**字段注释中引用其他表取值表达式*/
    public static final String COMMNET_REFERENCE_TABLE_EXPR = "关联(.+?)(\\s+|,|，|;|；|$)";

    /**记录每个修改字段的分隔符*/
    public static final String separator = ";";

    @Autowired
    private DataColumnService dataColumnService;

    @Autowired
    private GlobalCacheService globalCacheService;

    /**
     * 比较两个对象,并返回不一致的信息
     * @param  oldObj 旧对象
     * @param  newObj 新对象
     * @return
     */
    public String compareTwoObj(String operation,Object oldObj,Object newObj ) throws Exception {

        String str = "";//不一致的信息

        final BigDecimal BiGDecimal_0 = new BigDecimal(0);

        //获取对象的class
        Class<?> newClass = newObj.getClass();
        //获取对象的属性列表
        Field[] newFields = DataTypeUtil.getSuperField(newObj);

        String jsonStr = JSONObject.toJSONString(oldObj);//传过来的对象不一定是obj对象，可能是json对象，这里转成json对象，统一处理
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);

        Table table = newClass.getAnnotation(Table.class);
        String tablename = table.name();

        for (int i = 0; i < newFields.length; i++) {
            String column_name = newFields[i].getName();
            if ("serialVersionUID".equals(newFields[i].getName())) {
                continue;
            }
            if ("createTime".equalsIgnoreCase(column_name) || "createUserId".equalsIgnoreCase(column_name) || "updateTime".equalsIgnoreCase(column_name) || "updateUserId".equalsIgnoreCase(column_name)) {
                continue;
            }
            newFields[i].setAccessible(true);//设置可以进行访问，false时，会不允许访问安全检查

            // 获取FieldMeta注解属性
            FieldMeta fieldChinese = newFields[i].getAnnotation(FieldMeta.class);
            //判断是否有无注解，无注解时，取对象name，有注解时，取注解里的属性
            boolean fieldChineseIsEmpty = fieldChinese == null || StringUtils.isEmpty(fieldChinese.name());

            //获取FieldMeta注解中属性
            String fieldName = fieldChineseIsEmpty ? newFields[i].getName() : fieldChinese.name();
            String comment = fieldChineseIsEmpty ? newFields[i].getName() : fieldChinese.comment();
            String columnname = fieldChineseIsEmpty ? newFields[i].getName() : fieldChinese.columnname();

            PropertyDescriptor newPd = new PropertyDescriptor(newFields[i].getName(), newClass);
            Method newReadMethod = newPd.getReadMethod();
            //获取对应字段的值
            Object oldValue = jsonObject.get(DataTypeUtil.lineToHump(columnname));//旧对象通过jsonObject.get获取
            Object newValue = newReadMethod.invoke(newObj);//新对象直接invoke

            boolean isNeedTranslate = isNeedTranslate(comment);//判断是否需要翻译，如：性别,关联xt_dic.id，key='XT_DIC_GENDER'
            String refTableInfo = isNeedTranslate ? getReferenceTableInfo(tablename, columnname) : null;//如果需要翻译，则根据key获取翻译后的值

            if (DataTypeUtil.isEmptyStr(oldValue)) {
                if (!DataTypeUtil.isEmptyStr(newValue)) {
                    if (newValue instanceof java.util.Date) {
                        newValue = DateUtil.dateToStr_yyyyMMdd((java.util.Date)newValue);
                    }
                    /**获取差异字段*/
                    str = getDifferenceFieldStr(operation, str, fieldName, oldValue, newValue,refTableInfo);
                }
            } else {
                if (DataTypeUtil.isEmptyStr(oldValue)) {
                    if (isNumber(oldValue) && BiGDecimal_0.equals(DataTypeUtil.toBigDecimal(oldValue, BiGDecimal_0))) {

                    } else {
                        /**获取差异字段*/
                        str = getDifferenceFieldStr(operation, str, fieldName, oldValue, EMPTY_STR_VALUE,refTableInfo);
                    }
                } else {
                    // 都不为空，需要判断两者值是否相等
                    if (oldValue instanceof java.lang.String) {
                        String s_old = DataTypeUtil.toNotNullString(oldValue).trim();
                        String s_new = DataTypeUtil.toNotNullString(newValue).trim();
                        if (!s_old.toLowerCase().equals(s_new.toLowerCase())) {
                            /**获取差异字段*/
                            str = getDifferenceFieldStr(operation, str, fieldName, s_old, s_new,refTableInfo);
                        }
                    } else if (isNumber(oldValue)) {
                        BigDecimal bgOld = new BigDecimal(oldValue.toString());
                        BigDecimal bgNew = new BigDecimal("0");
                        if(newValue!=null){
                            bgNew = new BigDecimal(newValue.toString());
                        }
                        if(!bgOld.equals(bgNew)){
                            /**获取差异字段*/
                            str = getDifferenceFieldStr(operation, str, fieldName, bgOld, bgNew, refTableInfo);
                        }
                    } else if (oldValue instanceof java.util.Date) {
                        Date d_old = (Date)oldValue;
                        Date d_new = (Date)newValue;
                        int iDiff = DateUtil.diffDate(d_old, d_new);
                        if (iDiff != 0) {
                            /**获取差异字段*/
                            str = getDifferenceFieldStr(operation, str, fieldName, DateUtil.dateToStr(d_old, "yyyy-MM-dd"), DateUtil.dateToStr(d_new, "yyyy-MM-dd"),refTableInfo);
                        }
                    }
                }
            }
        }
        return str;
    }

    /**
     * 获取差异字段新旧值
     * @param msg
     * @param fieldName
     * @param oldValue
     * @param newValue
     * @return
     */
    private String getDifferenceFieldStr(String operation,String msg, String fieldName, Object oldValue, Object newValue,String refTableInfo) {
        if (!DataTypeUtil.isEmptyStr(msg)) {
            msg = msg + BR;
        }
        msg += fieldName;
        msg += ":";
        if (!SysConstant.OPER_ADD.equals(operation) && !SysConstant.OPER_DELETE.equals(operation)) {
            //更新情况下，记录值的变化，旧值到新值。
            msg += translateValue(oldValue, refTableInfo);
            msg += "-->";
        }
        msg += translateValue(newValue, refTableInfo);

        return msg;
    }


    // 注释中出现关联表时，取对应数据的名称进行友好显示
    private Object translateValue(Object idValue, String refTableInfo) {
        if(DataTypeUtil.isEmptyStr(refTableInfo)){
            return idValue;
        }
        return idValue + "@" + translateOnlyValue(idValue,refTableInfo);
    }


    public Object translateOnlyValue(Object idValue, String refTableInfo) {
        if (StringUtils.isEmpty(refTableInfo) || EMPTY_STR_VALUE.equals(idValue)) {
            return idValue;
        }
        String tableName = "";
        try {
            String[] arr = refTableInfo.split("\\.");
            tableName = DataTypeUtil.toNotNullString(arr[0]).trim();
            String idColumnName = DataTypeUtil.toNotNullString(arr[1]).trim();
            String nameColumnName = "name";
            if ("xt_upload_file".equalsIgnoreCase(tableName)) {
                nameColumnName = "file_name";
            }
            Object name = dataColumnService.translateColumnName(nameColumnName, tableName,idColumnName,DataTypeUtil.toNotNullString(idValue));
            return name;
        } catch (Exception e) {
            LoggerFactory.getLogger(ContrastUtils.class).error("翻译失败:tableName=" + tableName + ",refTableInfo=" + refTableInfo);
            LoggerFactory.getLogger(ContrastUtils.class).error(e.getMessage());
        }
        return idValue;
    }

    /*
     * 检查该段注释是否需要翻译，当出现【不用翻译】，【不翻译】关键字时则不翻译。
     */
    private boolean isNeedTranslate(String comment) {
        if (comment == null){
            return false;
        }
        if (!DataTypeUtil.isEmptyStr(NOT_NEED_TRANSLATE_COMMENT_KEYS)) {
            String[] arr = DataTypeUtil.str2arr(NOT_NEED_TRANSLATE_COMMENT_KEYS, ",");
            if (arr != null && arr.length > 0) {
                for (int i = 0; i < arr.length; i++) {
                    if (comment.indexOf(arr[i]) >= 0) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    /**
     *
     *返回一个字段的引用信息，用于引用表数据的显示
     * <BR>意义：显示变化ID所对应的值给用户看
     * @param tableName     表名称
     * @param columnName    列名称
     * @return  例如customerName
     * author zengting
     * @serialData 2020年3月2日
     */
    public String getReferenceTableInfo(String tableName, String columnName) {
        String comment = getDbComment(tableName, columnName);
        if (DataTypeUtil.isEmptyStr(comment)){
            return null;
        }
        String refTableInfo = null;
        try {
            refTableInfo = RegexUtil.getValueByRegex(comment, COMMNET_REFERENCE_TABLE_EXPR);
        } catch (Exception e) {
            LoggerFactory.getLogger(ContrastUtils.class).error(e.getMessage());
        }
        return refTableInfo;
    }

    /**
     * 取字段描述
     * @param tableName
     * @param columnName
     * @return
     * @author tsl
     * @serialData 2018年7月7日
     */
    public String getDbComment(String tableName, String columnName) {
        String key = (tableName + "." + columnName).toUpperCase();
        String comment = DataTypeUtil.toNotNullString(globalCacheService.getNameByCacheNameAndId(SysConstant.CACHE_USER_COL_COMMENTS,key));
        return comment;
    }

    private boolean isNumber(Object o) {
        boolean b = false;
        if (o instanceof java.lang.Integer) {
            b = true;
        } else if (o instanceof java.lang.Long) {
            b = true;
        } else if (o instanceof java.lang.Float) {
            b = true;
        } else if (o instanceof java.lang.Double) {
            b = true;
        } else if (o instanceof java.math.BigDecimal) {
            b = true;
        }
        return b;
    }


}